/*  
 *  Piece.cs - Base class for all chess pieces.
 *  Copyright(c) 2007 Adam W Adair
 *
 *  This file is part of Adam's Chess Engine (ACE).
 *
 *  ACE is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *   
 *  ACE is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with ACE; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;

namespace ACE.Board
{
    /// <summary>
    /// Piece is the base class for all chess pieces.
    /// </summary>
    abstract class Piece
    {
        // a piece will be either black or white.
        public enum PlayerColor { White, Black };
        // This was a mistake, and should have been made just ints.  Lessons learned.
        public const PlayerColor WHITE = PlayerColor.White;
        public const PlayerColor BLACK = PlayerColor.Black;

        public PlayerColor Color;
        protected int m_piecevalue;

        public Piece(PlayerColor color)
        {
            Color = color;
        }
        
        /// <summary>
        /// Integer value of the color.  0 = white, 1 = black
        /// </summary>
        public int ColorValue
        {
            get
            {
                return (int)Color;
            }
        }

        //public abstract int PieceSquareValue();

        /// <summary>
        /// The qualitative value of the piece.  Added a setter becuase this may need to be 
        /// adjustable in the engine.
        /// </summary>
        public int PieceValue
        {
            get{ return m_piecevalue; }
            set{ m_piecevalue = value;}
        }

        /// <summary>
        /// This should be overridden to return the lowercase character representation
        /// of the piece.  This should be the same character used in algebraic notation.
        /// </summary>
        public abstract string PieceChar
        {
            get;
        }

        /// <summary>
        /// true if the piece can move more than one space (bishop, rook, queen)
        /// </summary>
        public abstract bool CanSlide
        {
            get;
        }

        /// <summary>
        /// The offset vector for the piece.  This is how the piece moves on the board.
        /// </summary>
        public abstract int[] MoveOffsets
        {
            get;
        }

        /// <summary>
        /// Black pieces are displayed in lower case, white pieces in uppercase.
        /// </summary>
        public string DisplayChar
        {
            get
            {
                if (Color == PlayerColor.Black)
                {
                    return PieceChar;
                }
                return PieceChar.ToUpper();
            }
        }

        /// <summary>
        /// Generate all the potentially legal moves for this piece.  This procedure only
        /// makes sure that the moves stay on the board, do not pass though pieces, and
        /// do not capture same color pieces.  It does not check for other legalities such
        /// as putting own king in check.
        /// </summary>
        /// <param name="board">The board to generate moves for.</param>
        /// <param name="boardPosition">offset into the board</param>
        /// <returns></returns>
        public virtual List<Move> GeneratePotentialMoves(ChessBoard board, int boardPosition)
        {
            List<Move> ml = new List<Move>();  //move list
            Move move = null;
            int offset = 0;
            for (int i = 0; i < MoveOffsets.Length; ++i)
            {
                offset = MoveOffsets[i];
                for (int n = boardPosition; ; ) 
                {
                    n = ChessBoard.ValidationArray[ChessBoard.ValidationJump[n] + offset];
                    if (n == -1)
                        break;
                    if(board.Squares[n].Piece!=null)
                    {
                        if (board.Squares[n].Piece.Color != this.Color)
                        {
                            // Potential Capture, generate the move
                            move = new Move(boardPosition, n, this);
                            move.CapturePiece = board.Squares[n].Piece;
                            ml.Add(move);
                        }
                        //else, it is our piece so do not generate a move
                        break;
                    }
                    // generate a move to empty square.
                    move = new Move(boardPosition, n, this);
                    ml.Add(move);
                    if (!CanSlide)
                        break;
                }
            }
            return ml;
        }

        /// <summary>
        /// Checks to see if piece attack a square.  This algorithm is inefficient.  You may 
        /// have to revisit this method in the future. We may have to look at the direction
        /// of the square we are checking and use only the offset that go that direction. For
        /// now this will have to do.
        /// </summary>
        /// <param name="board">board position to check</param>
        /// <param name="piecePosition">the aquare the piece is sitting on</param>
        /// <param name="sqaure">the square to check</param>
        /// <returns>true if piece is attacking the square</returns>
        public virtual bool IsAttackingSqaure(ChessBoard board, int piecePosition, int sqaure)
        {
            int offset = 0;
            for (int i = 0; i < MoveOffsets.Length; ++i)
            {
                offset = MoveOffsets[i];
                for (int n = piecePosition; ; )
                {
                    n = ChessBoard.ValidationArray[ChessBoard.ValidationJump[n] + offset];
                    if (n == -1)
                        break;
                    if (n == sqaure)
                        return true;             
                    if (board.Squares[n].Piece != null)                    
                        break;
                    if (!CanSlide)
                        break;
                }
            }
            return false;
        }

    }
}
